package memberrank

import (
	"context"
	"encoding/json"
	"strconv"
	"strings"

	"mall/common/cachex"
	"mall/common/globalkey"
	"mall/common/utils/pointy"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/setting/rpc/settingclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type (
	// MemberRank is an interface to be customized, add more methods here,
	// and implement the added methods in customMemberRank.
	MemberRank interface {
		List() ([]*types.MemberRankInfo, error)
	}

	customMemberRank struct {
		ctx    context.Context
		svcCtx *svc.ServiceContext
	}
)

func NewMemberRank(ctx context.Context, svcCtx *svc.ServiceContext) MemberRank {
	return &customMemberRank{
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *customMemberRank) List() (resp []*types.MemberRankInfo, err error) {
	memberRankKey := cachex.LocalMemberRank

	localCacheMemberRankList, ok := l.svcCtx.LocalCache.Get(memberRankKey)
	if ok {
		resp = localCacheMemberRankList.([]*types.MemberRankInfo)
	} else {
		resp, err = l.list()
		if err != nil {
			return nil, err
		}

		l.svcCtx.LocalCache.Set(memberRankKey, resp)
	}

	return resp, nil
}

func (l *customMemberRank) list() (resp []*types.MemberRankInfo, err error) {
	var preload string = "memberRank:Id,Name,Code,Desc,PicId,PicUrl"
	preload += ";memberRankRestriction:Id,RankId,TaskId,Threshold" +
		";memberRankRule:Id,RankId,RuleType,Regions,Mode,Value,PeriodType,Quota"
	var eagerLoad string = "memberRank:memberRankRestriction,memberRankRule"
	var filters []string
	filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusEnabled), 10))
	res, err := l.svcCtx.SettingRpc.GetMemberRankList(l.ctx, &settingclient.BaseListReq{
		Preload:    &preload,
		EagerLoad:  &eagerLoad,
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		Sorter:     pointy.GetPointer("Sort:0"),
		PlatformId: pointy.GetPointer(globalkey.ThirdPartyPlatformWechatMini),
	})
	if err != nil {
		return nil, err
	}

	if len(res.List) > 0 {
		for _, v := range res.List {
			var restrictions []*types.MemberRankRestrictionInfo
			if len(v.Restrictions) > 0 {
				for _, rv := range v.Restrictions {
					restrictions = append(restrictions, &types.MemberRankRestrictionInfo{
						BaseIDInfo: types.BaseIDInfo{
							Id: v.Id,
						},
						RankId:    rv.RankId,
						TaskId:    rv.TaskId,
						Threshold: rv.Threshold,
					})
				}
			}
			var rules []*types.MemberRankRuleInfo
			if len(v.Rules) > 0 {
				for _, rv := range v.Rules {
					var regions []*types.TreeNode
					if rv.Regions != nil {
						if err := json.Unmarshal([]byte(*rv.Regions), &regions); err != nil {
							logx.Errorw("MemberRank List Rules.Regions json.Unmarshal err", logx.Field("detail", err.Error()))
						}
					}

					rules = append(rules, &types.MemberRankRuleInfo{
						BaseIDInfo: types.BaseIDInfo{
							Id: v.Id,
						},
						RankId:     rv.RankId,
						RuleType:   rv.RuleType,
						Regions:    regions,
						Mode:       rv.Mode,
						Value:      rv.Value,
						PeriodType: rv.PeriodType,
						Quota:      rv.Quota,
					})
				}
			}

			resp = append(resp, &types.MemberRankInfo{
				BaseIDInfo: types.BaseIDInfo{
					Id: v.Id,
				},
				Name:         v.Name,
				Code:         v.Code,
				Description:  v.Description,
				PicId:        v.PicId,
				PicUrl:       v.PicUrl,
				Restrictions: restrictions,
				Rules:        rules,
			})
		}
	}

	return resp, nil
}
